home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
vol11n06.zip
/
PCUNZP.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-01-27
|
59KB
|
1,918 lines
comment ~
Deziper
~
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START: JMP MAIN
; DATA AREA
; ---------
DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "PCUNZIP 1.0 Copyright (c) 1992 Michael J. Mefford",CR,LF
FIRST_RIGHTS DB "First Published in PC Magazine, March 31, 1992",CR,LF,LF
SYNTAX DB "Syntax: PCUNZIP filename [\path] [/v] [/e] [/o] [/?]",CR,LF,LF
DB "/e filespec = extract specific file",CR,LF
DB "/v [filespec] = view zipped files",CR,LF
DB "/o = overwrite any existing files",CR,LF,LF
DB "Putting a filename after /e will extract a specific; required",CR,LF
DB "Putting a filename after /v will list a specific file",CR,LF,LF,"$"
CR = 13
LF = 10
CTRL_Z = 26
SPACE = 32
BELL = 7
Y_SCAN = 15H
N_SCAN = 31H
TRUE = 1
FALSE = 0
KILOBYTES = 1024
PARAGRAPH = 16
DTA = 80H
MATCHING STRUC
RESERVED DB 21 DUP (?)
ATTR DB ?
DW ?
DW ?
DW ?
DW ?
FILE_NAME DB 13 DUP (?)
MATCHING ENDS
LOCAL_HEADER STRUC
SIGNATURE DB "PK",3,4
EXTRACT_VER DW ?
BIT_FLAG DW ?
ZIP_TYPE DW ?
FILE_TIME DW ?
FILE_DATE DW ?
CRC_32 DW ?,?
COMPRESS_SIZE DW ?,?
UNCOMPRESS_SIZE DW ?,?
FILENAME_LEN DW ?
EXTRA_FIELD_LEN DW ?
LOCAL_HEADER ENDS
LOCAL_SIG DB "PK",3,4
CENTRAL_SIG DB "PK",1,2
;Unshrink stuff
MIN_CODE_SIZE = 9
MAX_CODE_SIZE = 13
SPECIAL_CODE = 256
FIRST_FREE = 257
TRIE_SIZE = (1 SHL MAX_CODE_SIZE) + 1
FREE = -1
PREFIX_SIZE = TRIE_SIZE * 2 ;Word
SUFFIX_SIZE = TRIE_SIZE * 2 ;Char + void
READ_SIZE = 127 * 512
WRITE_SIZE = 127 * 512
DIR_SIZE = 66
LOCAL_STACK = 512
PREFIX_P = PREFIX_SIZE / PARAGRAPH
SUFFIX_P = SUFFIX_SIZE / PARAGRAPH
READ_P = READ_SIZE / PARAGRAPH
WRITE_P = WRITE_SIZE / PARAGRAPH
;Explode stuff
SF_TREE STRUC
BIT_LENGTH DB ?
VALUE DB ?
TREE_CODE DW ?
SF_TREE ENDS
LIT_TREE_SIZE = 256 * SIZE SF_TREE
LEN_TREE_SIZE = 64 * SIZE SF_TREE
DIST_TREE_SIZE = 64 * SIZE SF_TREE
TREE_ENTRIES = - 2
;Expand stuff
FOLLOWER STRUC
SET_LEN DB ?
SET DB 32 DUP (?)
PAD DB ?
FOLLOWER ENDS
READ_SEG DW ?
WRITE_SEG DW ?
DIR_LEN = 65
NAME_LEN = 12
ZIP_LEN = DIR_LEN + NAME_LEN
OUTFILE DB NAME_LEN DUP (?), 0
ZIP_NAME DB ZIP_LEN DUP (?), 0
DIR_NAME DB ZIP_LEN DUP (?), 0
SPECIFIC_NAME DB NAME_LEN DUP (?), 0
VIEW_NAME DB 39 DUP (?)
DB CR,LF,"$"
SEARCH_LEN DW ZIP_LEN
SEARCH_NAME DW ZIP_NAME
FREE_NODE DW FIRST_FREE * 2
EXTRACTOR DW ?
RUNNING_CRC_32 DW ?,?
BITS_LEFT DB ?
CODE_BITS DB ?
SAVE_BYTE DB ?
ATTRIBUTE DB ?
SPIN_CNT DB 0
SPIN_INDEX DW 0
SPINNERS DB "/|\"
SPECIFIC_FLAG DB FALSE ;=TRUE if extract individual file.
VIEW_FLAG DB FALSE ;=TRUE if view zipped files.
EXTRACTED_FLAG DB FALSE ;=TRUE if a file was extracted.
OVERWRITE_FLAG DB FALSE ;=TRUE if overwrite existing.
ZIP_EXT DB ".ZIP"
MEMORY_MSG DB "Not enough memory"
CR_LF_LF DB LF
CR_LF DB CR,LF,"$"
ZIP_MSG DB "Zip header not found$"
FAILED_MSG DB "Extracted file maybe corrupt",BELL,"$"
DISK_MSG DB "Not enough free disk space to extract file$"
ENCRYPTED_MSG DB "File is encrypted$"
NOT_FOUND_MSG DB "File not found$"
EXISTS_MSG DB " already exists. Overwrite (Y/N)?$"
UNKNOWN_MSG DB "Unknown compression method$"
INVALID_MSG DB "Invalid drive$"
DIR_MSG DB "Invalid target directory$"
SYNTAX_MSG DB "Syntax error$"
; CODE AREA
; ---------
MAIN PROC NEAR
CLD
XOR BH,BH
MOV AH,8
INT 10H
MOV ATTRIBUTE,AH
MOV BX,OFFSET STACK_POINTER + 15
MOV CL,4
SHR BX,CL
ADD BX,PREFIX_P + SUFFIX_P + READ_P + WRITE_P
MOV AH,4AH ;Allocate memory.
INT 21H
JNC SETUP_STACK
MOV DX,OFFSET MEMORY_MSG
JMP SHORT ERROR_EXIT ;If not enough, exit.
SETUP_STACK: MOV AX,OFFSET STACK_POINTER
MOV SP,AX ;Set up stack.
ADD AX,15
MOV CL,4
SHR AX,CL
MOV CX,DS
ADD AX,CX
ADD AX,PREFIX_P + SUFFIX_P
MOV READ_SEG,AX
ADD AX,READ_P
MOV WRITE_SEG,AX
CALL PARSE
JC ERROR_EXIT
MOV DX,OFFSET ZIP_NAME
XOR CX,CX
MOV AH,4EH
INT 21H
JMP SHORT DO_EXTRACT
NEXT_EXTRACT: CALL WRITE_CRLF
NEXT_EXTRACT2: MOV BX,READ_HANDLE
MOV AH,3EH
INT 21H
PUSH CS
POP ES
MOV AH,4FH
INT 21H
JNC DO_EXTRACT
GOOD_EXIT: XOR AL,AL
JMP SHORT EXIT
DO_EXTRACT: MOV SI,OFFSET DTA.FILE_NAME
MOV DI,OFFSET ZIP_NAME
CALL FORM_NAME
MOV DX,OFFSET ZIP_NAME
MOV AX,3D00H
INT 21H
MOV DX,OFFSET NOT_FOUND_MSG
JC ERROR_EXIT
MOV READ_HANDLE,AX
CALL EXTRACT
JNC NEXT_EXTRACT
CMP DX,OFFSET ZIP_MSG
JZ NEXT_EXTRACT2
ERROR_EXIT: PUSH DX
CALL WRITE_CRLF
POP DX
CALL PRINT_STRING
CALL WRITE_CRLFLF
MOV DX,OFFSET COPYRIGHT
CALL PRINT_STRING
MOV AL,1
EXIT: MOV AH,4CH
INT 21H
MAIN ENDP
;**************
; SUBROUTINES *
;**************
;OUTPUT: CF=1 if parse fail.
PARSE: MOV SEARCH_LEN,ZIP_LEN
MOV SEARCH_NAME,OFFSET ZIP_NAME
MOV SI,81H
NEXT_PARSE: CALL PARSE_DELIMIT
LODSB
CMP AL,CR
JZ PARSE_DONE
CMP AL,"-"
JZ SWITCH
CMP AL,"/"
JNZ DO_FILENAME
SWITCH: CALL PARSE_SWITCH
JC PARSE_END
JMP NEXT_PARSE
DO_FILENAME: DEC SI
MOV CX,SEARCH_LEN
MOV DI,SEARCH_NAME
CALL STORE_SEARCH
MOV SEARCH_LEN,DIR_LEN
MOV SEARCH_NAME,OFFSET DIR_NAME
JMP NEXT_PARSE
PARSE_DONE: MOV DX,OFFSET SYNTAX_MSG
CMP BYTE PTR ZIP_NAME,0
STC
JZ PARSE_END
MOV DX,OFFSET ZIP_NAME
XOR CX,CX
MOV AH,4EH
INT 21H
JNC FOUND_ZIP
CALL TACK_ZIP
MOV DX,OFFSET ZIP_NAME
XOR CX,CX
MOV AH,4EH
INT 21H
MOV DX,OFFSET NOT_FOUND_MSG
JC PARSE_END
FOUND_ZIP: CMP DIR_NAME,0
JZ PARSE_END
MOV SI,OFFSET DIR_NAME
NEXT_DIR_END: LODSB
OR AL,AL
JNZ NEXT_DIR_END
DEC SI
DEC SI
CMP BYTE PTR [SI],":"
JZ PARSE_END
MOV DX,OFFSET DIR_NAME
MOV CX,10H
MOV AH,4EH
INT 21H
MOV DX,OFFSET DIR_MSG
JC PARSE_END
TEST BYTE PTR DS:[DTA.ATTR],10H
STC
JZ PARSE_END
CMP BYTE PTR [SI],"\"
JZ PARSE_END
MOV BYTE PTR [SI+1],"\"
CLC
PARSE_END: RET
;----------------------;
PARSE_DELIMIT: LODSB
CMP AL,CR
JZ DELIMIT_END
CMP AL,SPACE
JBE PARSE_DELIMIT
DELIMIT_END: DEC SI
RET
;----------------------;
PARSE_SWITCH: CALL PARSE_DELIMIT
CMP AL,CR
JZ SWITCH_ERROR
LODSB
AND AL,5FH
CMP AL,"V"
JNZ CK_O
MOV VIEW_FLAG,TRUE
CALL PARSE_DELIMIT
CMP AL,CR
JZ SWITCH_GOOD
JMP SHORT DO_SPECIFIC
CK_O: CMP AL,"O"
JNZ CK_E
MOV OVERWRITE_FLAG,TRUE
JMP SHORT SWITCH_GOOD
CK_E: CMP AL,"E"
JNZ SWITCH_ERROR
CALL PARSE_DELIMIT
CMP AL,CR
JZ SWITCH_ERROR
MOV SPECIFIC_FLAG,TRUE
DO_SPECIFIC: MOV CX,NAME_LEN
MOV DI,OFFSET SPECIFIC_NAME
CALL STORE_SEARCH
SWITCH_GOOD: CLC
JMP SHORT SWITCH_END
SWITCH_ERROR: MOV DX,OFFSET SYNTAX_MSG
STC
SWITCH_END: RET
;----------------------;
; INPUT: DI-> storage; CX=length.
STORE_SEARCH: LODSB
CMP AL,CR
JZ STORE_DONE
CMP AL,SPACE
JBE STORE_END2
CMP AL,"a"
JB STORE_SEARCH2
CMP AL,"z"
JA STORE_SEARCH2
AND AL,5FH
STORE_SEARCH2: STOSB
LOOP STORE_SEARCH
JMP SHORT STORE_END2
STORE_DONE: DEC SI
STORE_END2: RET
;----------------------;
TACK_ZIP: MOV SI,OFFSET ZIP_NAME
MOV CX,ZIP_LEN - 4
NEXT_TACK: LODSB
CMP AL,"."
JZ TACK_IT
CMP AL,0
JZ TACK_IT
LOOP NEXT_TACK
JMP SHORT TACK_END
TACK_IT: DEC SI
MOV DI,SI
MOV SI,OFFSET ZIP_EXT
MOV CX,4
REP MOVSB
TACK_END: RET
;----------------------------------------------;
; INPUT: SI-> name; DI-> storage.
FORM_NAME: PUSH SI
MOV SI,DI
NEW_END: MOV BX,SI
FIND_END: LODSB
CMP AL,":"
JZ NEW_END
CMP AL,"\"
JZ NEW_END
OR AL,AL
JNZ FIND_END
POP SI
MOV DI,BX
FORM_NAME2: LODSB
STOSB
OR AL,AL
JNZ FORM_NAME2
RET
;----------------------------------------------;
;OUTPUT: If CF=1 then DX = failed msg.
EXTRACT: MOV BYTES_TO_READ[0],SIZE LOCAL_HEADER
MOV BYTES_TO_READ[2],0
CALL READ_ZIP
JNC CK_HEADER
JMP FAILED
CK_HEADER: MOV ES,READ_SEG
MOV SI,OFFSET LOCAL_SIG
XOR DI,DI
MOV CX,4
REPZ CMPSB
JZ PROCESS
MOV SI,OFFSET CENTRAL_SIG
XOR DI,DI
MOV CX,4
REPZ CMPSB
JNZ PROCESS_ERR
CLC
JMP EXTRACT_END
PROCESS_ERR: MOV DX,OFFSET ZIP_MSG
PROCESS_ERR2: JMP FAILED2
PROCESS: CALL PROCESS_HEADER
JNC PROCESS2
JMP FAILED2
PROCESS2: CALL READ_ZIP
JC LILLY_FAIL
MOV BYTES_TO_READ[0],AX
MOV BYTES_TO_READ[2],BX
CALL GET_FILENAME
JC EXTRACT
MOV DX,OFFSET DIR_NAME
XOR CX,CX
MOV AH,3CH
INT 21H
LILLY_FAIL: JC FAILED
MOV WRITE_HANDLE,AX
MOV RUNNING_CRC_32[0],-1
MOV RUNNING_CRC_32[2],-1
CMP BYTES_TO_READ[0],0
JNZ PROCESS3
CMP BYTES_TO_READ[2],0
JZ PROCESS4
PROCESS3: CALL READ_ZIP
JC FAILED
MOV SAVE_BYTE,0
MOV BITS_LEFT,0
CALL [EXTRACTOR]
PUSHF
MOV AL,SPACE
CALL SPIN_IT
CALL WRITE_CRLFLF
POPF
JC FAILED
CALL WRITE
JC FAILED
PROCESS4: MOV BX,WRITE_HANDLE
MOV CX,TIME_STAMP
MOV DX,DATE_STAMP
MOV AX,5701H
INT 21H
JC FAILED
MOV AH,3EH
INT 21H
CALL CK_CRC
JC FAILED
CMP BYTES_TO_READ[0],0
JNZ FAILED
CMP BYTES_TO_READ[2],0
JNZ FAILED
MOV EXTRACTED_FLAG,TRUE
JMP EXTRACT
FAILED: MOV DX,OFFSET FAILED_MSG
FAILED2: STC
EXTRACT_END: RET
;----------------------------------------------;
; INPUT:CX=FILENAME_LEN; OUTPUT: CF=1 if skipped.
END_FILENAME DW ?
GET_FILENAME: MOV AX,CS
MOV ES,AX
MOV DI,OFFSET OUTFILE
PUSH DS
MOV DS,READ_SEG
XOR SI,SI
NEXT_FILENAME: LODSB
CMP AL,"/"
JNZ STORE_NAME
MOV DI,OFFSET OUTFILE
JMP SHORT STORE_NAME2
STORE_NAME: STOSB
STORE_NAME2: LOOP NEXT_FILENAME
MOV SI,DI
XOR AL,AL
STOSB
POP DS
MOV SI,OFFSET OUTFILE
MOV DI,OFFSET DIR_NAME
CALL FORM_NAME
DEC DI
MOV END_FILENAME,DI
CALL VIEW_OR_SPEC
JC FILENAME_END
MOV DX,OFFSET DIR_NAME
MOV AX,3D00H
INT 21H
CMC
JNC FILENAME_END
MOV BX,AX
MOV AH,3EH
INT 21H
CMP OVERWRITE_FLAG,TRUE
CLC
JZ FILENAME_END
CALL WRITE_FILENAME
MOV DX,OFFSET EXISTS_MSG
CALL PRINT_STRING
CK_KEY: MOV AH,1 ;Is there a keystroke available.
INT 16H
JZ NEXT_KEY
CLEAR_IT: XOR AH,AH
INT 16H
JMP CK_KEY
NEXT_KEY: XOR AH,AH
INT 16H
CLC
CMP AH,Y_SCAN
JZ CONTINUE
CMP AL,3 ;Ctrl break
JNZ CK_N
JMP GOOD_EXIT
CK_N: CMP AH,N_SCAN
JNZ NEXT_KEY
MOV DX,BYTES_TO_READ[0]
MOV CX,BYTES_TO_READ[2]
MOV BX,READ_HANDLE
MOV AX,4201H
INT 21H
STC
CONTINUE: PUSHF
CALL WRITE_CRLFLF
POPF
FILENAME_END: RET
;----------------------;
; OUTPUT: CF=1 of should not be extracted.
VIEW_OR_SPEC: CMP VIEW_FLAG,TRUE
JNZ CK_SPECIFIC
CMP SPECIFIC_NAME,0
JZ DO_DISPLAY
CALL CK_MATCH
JC ADVANCE_FILE
DO_DISPLAY: CALL DISPLAY_NAME
JMP SHORT ADVANCE_FILE
CK_SPECIFIC: CMP SPECIFIC_FLAG,TRUE
CLC
JNZ V_OR_S_END
CALL CK_MATCH
JNC V_OR_S_END
ADVANCE_FILE: MOV DX,BYTES_TO_READ[0]
MOV CX,BYTES_TO_READ[2]
MOV BX,READ_HANDLE
MOV AX,4201H
INT 21H
JC V_OR_S_END
CMC
V_OR_S_END: RET
;----------------------;
; OUTPUT: CF=1 if no match.
CK_MATCH: MOV SI,OFFSET SPECIFIC_NAME
MOV DI,OFFSET OUTFILE
NEXT_NAME: LODSB
MOV AH,[DI]
CMP AL,"*"
JZ FIND_DOT
CK_Q: CMP AL,"?"
JNZ COMPARE_NAME
OR AH,AH
JZ NEXT_NAME
CMP AH,"."
JZ NEXT_NAME
INC DI
JMP NEXT_NAME
COMPARE_NAME: INC DI
CMP AL,AH
JNZ NO_MATCH
OR AL,AL
JZ MATCH
CMP AL,"."
JNZ NEXT_NAME
JMP SHORT NEXT_EXT
FIND_DOT: LODSB
CMP AL,"."
JZ DO_OUTFILE
OR AL,AL
JNZ FIND_DOT
DEC SI
DO_OUTFILE: MOV AL,[DI]
OR AL,AL
JZ NEXT_EXT
INC DI
CMP AL,"."
JNZ DO_OUTFILE
NEXT_EXT: LODSB
MOV AH,[DI]
CMP AL,"*"
JZ MATCH
CMP AL,"?"
JNZ COMPARE_EXT
OR AH,AH
JZ NEXT_EXT
INC DI
JMP NEXT_EXT
COMPARE_EXT: INC DI
CMP AL,AH
JNZ NO_MATCH
OR AL,AL
JNZ NEXT_EXT
MATCH: CLC
JMP SHORT CK_MATCH_END
NO_MATCH: STC
CK_MATCH_END: RET
;----------------------;
DISPLAY_NAME: MOV EXTRACTED_FLAG,TRUE
MOV DI,OFFSET VIEW_NAME
MOV AL,SPACE
MOV CX,SIZE VIEW_NAME
REP STOSB
MOV SI,OFFSET OUTFILE ;Point to filename.
MOV DI,OFFSET VIEW_NAME
MOV CX,NAME_LEN ;Store 12 bytes of filename.
JMP SHORT NEXT_STORE2
EXTENSION: ADD DI,CX
MOV CX,3
SUB DI,CX
NEXT_STORE2: LODSB ;Get a byte.
OR AL,AL ;End of filename?
JZ END_STORE ;If yes, finish with blanks.
CMP AL,"." ;Is it the period?
JZ EXTENSION
STOSB ;Store byte.
LOOP NEXT_STORE2 ;Get next byte.
END_STORE: ADD DI,CX
STORE_SIZE: PUSH DI ;Save pointer.
ADD DI,8 ;Move to end of bytes field.
MOV DX,SIZE_LOW ;Retrieve high and low words
MOV AX,SIZE_HIGH ; of size in bytes.
MOV BX,10
STD ;Reverse direction.
NEXT_SIZE: MOV CX,DX ;Low word in CX.
XOR DX,DX ;Zero in high half.
DIV BX ;Convert to decimal.
XCHG AX,CX ;Retrieve low word.
DIV BX
XCHG AX,DX ;Retrieve remainder.
ADD AL,"0" ;Convert to ASCII.
STOSB ;Store it.
MOV AX,CX ;Are we done?
OR CX,DX
JNZ NEXT_SIZE ;If no, divide again.
CLD ;Back to forward direction.
POP DI ;Retrieve pointer.
ADD DI,11 ;Move to date field.
STORE_DATE: MOV DX,DATE_STAMP ;Retrieve date.
MOV AX,DX
MOV CL,5 ;Shift to lowest bits.
SHR AX,CL
AND AX,1111B ;Mask off all but month.
MOV CL,0FFH ;Flag as no leading zeros.
MOV CH,"-" ;Delimiting character.
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date.
AND AX,11111B ;Mask off all but day.
XOR CL,CL ;Flag include leading zeros.
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date for last time.
MOV CL,9
SHR AX,CL ;Mask off all but year.
ADD AX,80 ;Adjust to ASCII.
CMP AX,100 ;Past year 2000?
JB DISPLAY_DATE ;If no, display. Else, adjust for
SUB AX,100 ; next century. (Planning ahead!)
DISPLAY_DATE: XOR CL,CL ;Display leading zeros.
MOV CH,SPACE
CALL STORE_WORD ;Store it.
TIME: INC DI ;Move to time field.
MOV DX,TIME_STAMP ;Retrieve time.
MOV AX,DX
MOV CL,11 ;Shift to hours bits.
SHR AX,CL
PUSH AX
CMP AX,12 ;Past noon?
JBE MERIDIAN
SUB AX,12 ;If yes, adjust.
MERIDIAN: CMP AX,0 ;Midnight?
JNZ NOT_MIDNIGHT
MOV AX,12 ;If yes, adjust.
NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
MOV CH,":"
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve time.
MOV CL,5 ;Shift to minutes bits.
SHR AX,CL
AND AX,111111B ;Mask off all but minutes.
XOR CL,CL
POP DX ;Retrieve hours.
MOV CH,"p" ;Assume PM.
CMP DX,12 ;Is it PM?
JAE PM
MOV CH,"a" ;If no, AM.
PM: CALL STORE_WORD ;Store it.
MOV DX,OFFSET VIEW_NAME
MOV AH,9H
INT 21H
RET
;-----------------------------------------------------------------------;
; Converts a two byte hex number to decimal followed by delimiter. ;
; INPUT: AX = hex number; BL = 10; CH = delimiter character to store. ;
; CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
; ES:DI points to storage. ;
;-----------------------------------------------------------------------;
STORE_WORD: DIV BL ;Divide by ten.
ADD AX,"00" ;Convert to ASCII.
CMP CL,0 ;Are we to display leading zero?
JZ STORE_IT ;If yes, store as is.
CMP AL,"0" ;Is it a leading zero?
JNZ STORE_IT ;If no, store it.
MOV AL,SPACE ;Else, store a space.
STORE_IT: STOSW
MOV AL,CH ;Store delimiter character also.
STOSB
RET
;----------------------------------------------;
;OUTPUT: AX=COMPRESS_SIZE[0]; BX=COMPRESS_SIZE[2]; CX=FILENAME_LEN;
; CF=1 if failed.
COMPRESS_FLAG DB ?
TIME_STAMP DW ?
DATE_STAMP DW ?
FILE_CRC DW ?,?
SIZE_HIGH DW ?
SIZE_LOW DW ?
REDUCE_L DW ?
REDUCE_F DW ?
REDUCE_D1 DB ?
REDUCE_D2 DW ?
PROCESS_HEADER:PUSH DS
MOV DS,READ_SEG
MOV AX,DS:BIT_FLAG
MOV CS:COMPRESS_FLAG,AL
TEST AX,1
MOV DX,OFFSET ENCRYPTED_MSG
JNZ PROCESS_FAIL
CALL PROCESS_TYPE
MOV DX,OFFSET UNKNOWN_MSG
JC PROCESS_FAIL
XOR DL,DL
MOV AH,36H
INT 21H
CMP AX,0FFFFH
MOV DX,OFFSET INVALID_MSG
JZ PROCESS_FAIL
MUL BX
MUL CX
SUB AX,DS:UNCOMPRESS_SIZE[0]
SBB DX,DS:UNCOMPRESS_SIZE[2]
MOV DX,OFFSET DISK_MSG
JC PROCESS_FAIL
MOV AX,DS:UNCOMPRESS_SIZE[0]
MOV CS:SIZE_LOW,AX
MOV AX,DS:UNCOMPRESS_SIZE[2]
MOV CS:SIZE_HIGH,AX
MOV CX,DS:FILENAME_LEN
MOV DX,DS:EXTRA_FIELD_LEN
ADD DX,CX
MOV AX,DS:COMPRESS_SIZE[0]
MOV BX,DS:COMPRESS_SIZE[2]
MOV SI,DS:FILE_TIME
MOV DI,DS:FILE_DATE
MOV BP,DS:CRC_32[0]
MOV CS:FILE_CRC[0],BP
MOV BP,DS:CRC_32[2]
CLC
JMP SHORT PROCESS_END
PROCESS_FAIL: STC
PROCESS_END: POP DS
MOV FILE_CRC[2],BP
MOV BYTES_TO_READ[0],DX
MOV TIME_STAMP,SI
MOV DATE_STAMP,DI
RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
PROCESS_TYPE: MOV BX,DS:ZIP_TYPE
MOV AX,OFFSET UNSTORE
OR BX,BX
JZ STORE_EXTRACT
MOV AX,OFFSET UNSHRINK
DEC BX
JZ STORE_EXTRACT
MOV AX,OFFSET EXPAND
MOV DX,7FH
MOV CX,701H
DEC BX
JZ STORE_EXPAND
MOV DX,3FH
MOV CX,603H
DEC BX
JZ STORE_EXPAND
MOV DX,1FH
MOV CX,507H
DEC BX
JZ STORE_EXPAND
MOV DX,0FH
MOV CX,40FH
DEC BX
JNZ CK_EXPLODE
STORE_EXPAND: MOV CS:REDUCE_L,DX
MOV CS:REDUCE_F,DX
MOV CS:REDUCE_D1,CH
XOR CH,CH
MOV CS:REDUCE_D2,CX
JMP SHORT STORE_EXTRACT
CK_EXPLODE: MOV AX,OFFSET EXPLODE
DEC BX
JZ STORE_EXTRACT
STC
JMP SHORT TYPE_END
STORE_EXTRACT: MOV CS:EXTRACTOR,AX
CLC
TYPE_END: RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
CK_CRC: MOV AX,RUNNING_CRC_32[0]
MOV DX,RUNNING_CRC_32[2]
XOR AX,0FFFFH
XOR DX,0FFFFH
CMP AX,FILE_CRC[0]
STC
JNZ CRC_END
CMP DX,FILE_CRC[2]
STC
JNZ CRC_END
CLC
CRC_END: RET
;**********************************************;
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
;**********************************************;
EXTRACT_MSG DB "Extracting $"
UNSTORE: MOV DX,OFFSET EXTRACT_MSG
CALL PRINT_STRING
CALL WRITE_FILENAME
UNSTORE_SPIN: CALL SPINNER
NEXT_UNSTORE: INC SPIN_CNT
JZ UNSTORE_SPIN
MOV ES,READ_SEG
MOV SI,READ_PTR
CMP SI,BYTES_READ
JZ GET_BYTES2
MOV AL,ES:[SI]
INC READ_PTR
CALL STORE_CHAR
JNC NEXT_UNSTORE
CLC
JMP SHORT UNSTORE_END
GET_BYTES2: CALL READ_ZIP
JNC NEXT_UNSTORE
CLC
UNSTORE_END: RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
EXPAND_MSG DB "Expanding $"
STATE DW ?
LAST_CHAR DB ?
EXPAND: MOV DX,OFFSET EXPLODE_MSG
CALL PRINT_STRING
CALL WRITE_FILENAME
MOV WRITE_FLAG,0
MOV LAST_CHAR,0
MOV STATE,OFFSET STATE_ZERO
CALL LOAD_FOLLOWERS
JC EXPAND_END
EXPAND_SPIN: CALL SPINNER
NEXT_EXPAND: INC SPIN_CNT
JZ EXPAND_SPIN
MOV AX,SIZE FOLLOWER
MUL LAST_CHAR
MOV BP,AX
CMP BYTE PTR FOLLOWERS[BP],0
JNZ GET_BIT
MOV BL,8
CALL GET_CODE
JNC DO_EXPAND
JMP SHORT EXPAND_END
GET_BIT: MOV BL,1
CALL GET_CODE
JC EXPAND_END
OR AL,AL
JZ GET_FOLLOW
MOV BL,8
CALL GET_CODE
JNC DO_EXPAND
JMP SHORT EXPAND_END
GET_FOLLOW: MOV BH,FOLLOWERS[BP]
SUB BH,1
JC EXPAND_ERR
MOV BL,8
JMP SHORT NEXT_BIT2
NEXT_BIT: DEC BL
NEXT_BIT2: SHL BH,1
JNC NEXT_BIT
CALL GET_CODE
JC EXPAND_END
MOV SI,AX
INC SI
MOV AL,FOLLOWERS[BP+SI]
XOR AH,AH
DO_EXPAND: MOV LAST_CHAR,AL
CALL [STATE]
JNC NEXT_EXPAND
EXPAND_ERR: STC
JMP SHORT EXPAND_END2
EXPAND_END: CLC
EXPAND_END2: RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
LOAD_FOLLOWERS:MOV BP,255 * SIZE FOLLOWER
NEXT_FOLLOW: MOV BL,6
CALL GET_CODE
JC FOLLOWERS_END
MOV FOLLOWERS[BP],AL
OR AL,AL
JZ LOOP_FOLLOW
XOR DI,DI
NEXT_FOLLOW2: MOV BL,8
CALL GET_CODE
JC FOLLOWERS_END
INC DI
MOV FOLLOWERS[BP+DI],AL
MOV AX,DI
CMP AL,FOLLOWERS[BP]
JB NEXT_FOLLOW2
LOOP_FOLLOW: SUB BP,SIZE FOLLOWER
JNC NEXT_FOLLOW
CLC
FOLLOWERS_END: RET
;----------------------------------------------;
; INPUT: AL=Char; OUTPUT: CF=1 if failed.
DLE = 144
STATE_ZERO: CMP AL,DLE
JZ CHANGE_STATE
CALL STORE_CHAR
RET
CHANGE_STATE: MOV STATE,OFFSET STATE_ONE
CLC
ZERO_END: RET
;----------------------------------------------;
; INPUT: AL=Char; OUTPUT: CF=1 if failed.
SAVE_REDUCE DW ?
EXPAND_LEN DW ?
STATE_ONE: OR AL,AL
JZ WRITE_DLE
MOV SAVE_REDUCE,AX
AND AX,REDUCE_L
MOV EXPAND_LEN,AX
MOV BX,OFFSET STATE_THREE
CMP AX,REDUCE_F
JNZ SAVE_STATE
MOV BX,OFFSET STATE_TWO
SAVE_STATE: MOV STATE,BX
CLC
RET
WRITE_DLE: MOV AL,DLE
CALL STORE_CHAR
MOV STATE,OFFSET STATE_ZERO
RET
;----------------------------------------------;
; INPUT: AL=Char; OUTPUT: CF=1 if failed.
STATE_TWO: ADD EXPAND_LEN,AX
MOV STATE,OFFSET STATE_THREE
CLC
RET
;----------------------------------------------;
; INPUT: AL=Char; OUTPUT: CF=1 if failed.
STATE_THREE: MOV BX,SAVE_REDUCE
MOV CL,REDUCE_D1
SHR BX,CL
AND BX,REDUCE_D2
MOV CL,8
SHL BX,CL
ADD BX,AX
INC BX
MOV CX,EXPAND_LEN
INC CX
INC CX
INC CX
CALL BACKWARDS
MOV STATE,OFFSET STATE_ZERO
RET
;**********************************************;
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
EXPLODE_MSG DB "Exploding $"
DISTANCE DW ?
DICT_BITS DB ?
MIN_MATCH_LEN DW ?
WRITE_FLAG DB ?
EXPLODE: MOV DX,OFFSET EXPLODE_MSG
CALL PRINT_STRING
CALL WRITE_FILENAME
MOV WRITE_FLAG,0
CALL LOAD_TREES
JC LILLY_EXIT4
EXPLODE_SPIN: CALL SPINNER
NEXT_EXPLODE: INC SPIN_CNT
JZ EXPLODE_SPIN
MOV BL,1
CALL GET_CODE
JC LILLY_EXIT3
OR AX,AX
JZ SLIDING_DICT
TEST COMPRESS_FLAG,100B
JZ GET_A_CODE
MOV BP,OFFSET LIT_TREE
CALL READ_TREE
JC LILLY_EXIT3
JMP SHORT STORE_BYTE
GET_A_CODE: MOV BL,8
CALL GET_CODE
JC LILLY_EXIT3
STORE_BYTE: CALL STORE_CHAR
JNC NEXT_EXPLODE
JMP EXPLODE_END2
LILLY_EXIT3: CLC
LILLY_EXIT4: JMP EXPLODE_END2
SLIDING_DICT: MOV BL,DICT_BITS
CALL GET_CODE
JC EXPLODE_END2
MOV DISTANCE,AX
MOV BP,OFFSET DISTANCE_TREE
CALL READ_TREE
JC EXPLODE_END2
MOV CL,DICT_BITS
SHL AX,CL
OR DISTANCE,AX
MOV BP,OFFSET LENGTH_TREE
CALL READ_TREE
JC EXPLODE_END2
MOV DI,AX
ADD AX,MIN_MATCH_LEN
CMP DI,63
JNZ DO_BACKWARDS
MOV DI,AX
MOV BL,8
CALL GET_CODE
JC EXPLODE_END
ADD AX,DI
DO_BACKWARDS: MOV CX,AX ;Length
MOV BX,DISTANCE
INC BX
CALL BACKWARDS
JNC NEXT_EXPLODE
JMP SHORT EXPLODE_END2
EXPLODE_END: CLC
EXPLODE_END2: RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
LOAD_TREES: MOV AL,COMPRESS_FLAG
MOV AH,7
TEST AL,10B
JNZ STORE_DICT
DEC AH
STORE_DICT: MOV DICT_BITS,AH
MOV MIN_MATCH_LEN,2
TEST AL,100B
JZ OTHER_TREES
MOV MIN_MATCH_LEN,3
MOV BP,OFFSET LIT_TREE
MOV WORD PTR TREE_ENTRIES[BP],256
CALL LOAD_TREE
JC LOAD_TR_END
OTHER_TREES: MOV BP,OFFSET LENGTH_TREE
MOV WORD PTR TREE_ENTRIES[BP],64
CALL LOAD_TREE
JC LOAD_TR_END
MOV BP,OFFSET DISTANCE_TREE
MOV WORD PTR TREE_ENTRIES[BP],64
CALL LOAD_TREE
LOAD_TR_END: RET
;----------------------------------------------;
; INPUT: BP=Tree index. OUTPUT: CF=1 if failed.
LOAD_TREE: CALL READ_LEN
JC LOAD_TREE_END
CALL SORT_LEN
CALL MAKE_TREE
CALL REVERSE_BITS
CLC
LOAD_TREE_END: RET
;----------------------------------------------;
; INPUT: BP=Tree index. OUTPUT: CF=1 if failed.
TREE_BYTES DB ?
READ_LEN: MOV BL,8
CALL GET_CODE
JC READ_LEN_END
INC AX
MOV TREE_BYTES,AL
XOR DI,DI
NEXT_LEN: MOV BL,8
CALL GET_CODE
JC READ_LEN_END
MOV AH,AL
MOV CL,4
SHR AH,CL
AND AL,0FH
INC AH
INC AL
NEXT_LEN2: MOV CX,DI
MOV SI,DI
SHL SI,1
SHL SI,1
MOV BIT_LENGTH[BP+SI],AL
MOV VALUE[BP+SI],CL
INC DI
DEC AH
JNZ NEXT_LEN2
DEC TREE_BYTES
JNZ NEXT_LEN
CLC
READ_LEN_END: RET
;----------------------------------------------;
; INPUT: BP=Tree index.
SORT_LEN: MOV AX,CS
MOV ES,AX
MOV AX,SIZE SF_TREE
MUL WORD PTR TREE_ENTRIES[BP]
ADD AX,BP
MOV CX,BP
NEXT_SORT: MOV BX,CX
MOV DX,CX
ADD DX,SIZE SF_TREE
CMP DX,AX
JAE SORT_END
NEXT_SORT2: MOV SI,BX
MOV DI,DX
CMPSB
JB LOOP_SORT
JA SORT_IT
CMPSB
JBE LOOP_SORT
DEC SI
DEC DI
SORT_IT: DEC SI
DEC DI
PUSH [DI]
MOVSW
POP [BX]
LOOP_SORT: ADD DX,SIZE SF_TREE
CMP DX,AX
JB NEXT_SORT2
ADD CX,SIZE SF_TREE
JMP NEXT_SORT
SORT_END: RET
;----------------------------------------------;
; INPUT: BP=Tree index.
MAKE_TREE: MOV AX,SIZE SF_TREE
MUL WORD PTR TREE_ENTRIES[BP]
ADD AX,BP
MOV SI,AX
XOR AX,AX ;Code
XOR BL,BL ;Last bit length
XOR DI,DI ;Code increment
NEXT_MAKE: SUB SI,SIZE SF_TREE
CMP SI,BP
JB MAKE_END
ADD AX,DI
MOV TREE_CODE[SI],AX
MOV BH,BIT_LENGTH[SI]
CMP BH,BL
JZ NEXT_MAKE
MOV BL,BH
MOV CL,16
SUB CL,BL
MOV DI,1
SHL DI,CL
JMP NEXT_MAKE
MAKE_END: RET
;----------------------------------------------;
; INPUT: BP=Tree index.
REVERSE_BITS: MOV DX,TREE_ENTRIES[BP]
MOV SI,BP
NEXT_REV: INC SI
INC SI ;Code
LODSW
XOR BX,BX
MOV CX,16
NEXT_REV2: SHR AX,1
RCL BX,1
LOOP NEXT_REV2
MOV [SI-2],BX
DEC DX
JNZ NEXT_REV
RET
;----------------------------------------------;
; INPUT: BP=Tree index. OUTPUT: AX=code; CF=1 if failed.
INDEX DW ?
BITS DB ?
READ_TREE: XOR DI,DI ;Code
XOR DX,DX ;Bit length
XOR CL,CL ;Bits
NEXT_READ_T: MOV BITS,CL
MOV BL,1
CALL GET_CODE
JC READ_T_END2
MOV CL,BITS
SHL AX,CL
OR DI,AX
INC CL
MOV SI,DX
NEXT_READ_T2: SHL SI,1
SHL SI,1
CMP BIT_LENGTH[BP+SI],CL
JA NEXT_READ_T
JZ NEXT_READ_T3
INC DX
MOV SI,DX
CMP SI,TREE_ENTRIES[BP]
JB NEXT_READ_T2
JMP TREE_ERROR
NEXT_READ_T3: CMP TREE_CODE[BP+SI],DI
JNZ LOOP_TREE
MOV AL,VALUE[BP+SI]
XOR AH,AH
JMP SHORT READ_T_END
LOOP_TREE: INC DX
MOV SI,DX
CMP SI,TREE_ENTRIES[BP]
JAE TREE_ERROR
SHL SI,1
SHL SI,1
CMP BIT_LENGTH[BP+SI],CL
JZ NEXT_READ_T3
JMP NEXT_READ_T
TREE_ERROR: STC
JMP SHORT READ_T_END2
READ_T_END: CLC
READ_T_END2: RET
;----------------------------------------------;
; INPUT: CX=Length; BX=Distance; OUTPUT: CF=1 if failed.
BACKWARDS: MOV ES,WRITE_SEG
MOV SI,WRITE_PTR
SUB SI,BX
JNC NEXT_BACK
CMP WRITE_FLAG,1
JZ END_BUFF
NEXT_NULL: OR SI,SI
JZ NEXT_BACK
XOR AL,AL
CALL STORE_CHAR
JC BACKWARDS_END
INC SI
LOOP NEXT_NULL
JMP BACKWARDS_END
END_BUFF: ADD SI,WRITE_SIZE
NEXT_BACK: MOV AL,ES:[SI]
CALL STORE_CHAR
JC BACKWARDS_END
INC SI
CMP SI,WRITE_SIZE
JNZ LOOP_BACK
XOR SI,SI
LOOP_BACK: LOOP NEXT_BACK
CLC
BACKWARDS_END: RET
;**********************************************;
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
BASE_CHAR DB ?
PREV_CODE DW ?
SAVE_CODE DW ?
UNSHRINK_MSG DB "Unshrinking $"
UNSHRINK: MOV DX,OFFSET UNSHRINK_MSG
CALL PRINT_STRING
CALL WRITE_FILENAME
CALL INIT_UNSHRINK
MOV BL,CODE_BITS
CALL GET_CODE
JC LILLY_EXIT
MOV PREV_CODE,AX
MOV BASE_CHAR,AL
CALL STORE_CHAR
JC LILLY_EXIT2
UNSHRINK_SPIN: CALL SPINNER
NEXT_UNSHRINK: INC SPIN_CNT
JZ UNSHRINK_SPIN
MOV BL,CODE_BITS
CALL GET_CODE
JC LILLY_EXIT
MOV SAVE_CODE,AX
XOR CX,CX ;String counter.
CMP AX,SPECIAL_CODE
JB STORE_UNSHRUNK
JA CK_ERROR
MOV BL,CODE_BITS
CALL GET_CODE
JC LILLY_EXIT
DEC AX
JNZ CK_CLEAR
INC CODE_BITS
JMP NEXT_UNSHRINK
CK_CLEAR: DEC AX
STC
JNZ LILLY_EXIT2
CALL CLEAR
JMP NEXT_UNSHRINK
LILLY_EXIT: CLC
LILLY_EXIT2: JMP UNSHRINK_END
CK_ERROR: CMP AX,TRIE_SIZE
JA ERROR
MOV BX,AX
SHL BX,1
CMP WORD PTR PREFIX[BX],FREE
JNZ FIND_STRING2
PUSH WORD PTR BASE_CHAR
INC CX
MOV BX,PREV_CODE
CMP BX,FIRST_FREE
JB GOT_UNSHRUNK
FIND_STRING: SHL BX,1
FIND_STRING2: PUSH SUFFIX[BX]
INC CX
MOV BX,PREFIX[BX]
CMP BX,FIRST_FREE
JAE FIND_STRING
GOT_UNSHRUNK: MOV AL,BL
STORE_UNSHRUNK:MOV BASE_CHAR,AL
CALL STORE_CHAR
JC UNSHRINK_END
JCXZ ADD_CODE
NEXT_STORE: POP AX
CALL STORE_CHAR
JC UNSHRINK_END
LOOP NEXT_STORE
ADD_CODE: MOV DI,FREE_NODE
MOV AL,BASE_CHAR
MOV SUFFIX[DI],AL
MOV AX,PREV_CODE
MOV PREFIX[DI],AX
NEXT_FREE: INC DI
INC DI
CMP DI,TRIE_SIZE * 2
JA ERROR
CMP WORD PTR PREFIX[DI],FREE
JNZ NEXT_FREE
MOV FREE_NODE,DI
MOV AX,SAVE_CODE
MOV PREV_CODE,AX
JMP NEXT_UNSHRINK
ERROR: STC
UNSHRINK_END: RET
;----------------------------------------------;
INIT_UNSHRINK: PUSH CS
POP ES
MOV DI,OFFSET PREFIX
MOV AX,FREE
MOV CX,TRIE_SIZE
REP STOSW
MOV FREE_NODE,FIRST_FREE * 2
MOV CODE_BITS,MIN_CODE_SIZE
RET
;----------------------------------------------;
; INPUT: BITS_LEFT; BL=CODE_BITS; OUTPUT: AX=code; CF=1 if EOF or failed.
GET_CODE: MOV CL,BL
XOR AX,AX
MOV BH,BITS_LEFT
OR BH,BH
JZ GET_BITS
MOV CH,SAVE_BYTE
NEXT_SHIFT2: SHR CH,1
RCR AX,1
DEC BL
JZ GOT_CODE
DEC BH
JNZ NEXT_SHIFT2
GET_BITS: MOV SI,READ_PTR
CMP SI,BYTES_READ
JZ GET_BYTE
MOV ES,READ_SEG
MOV CH,ES:[SI]
INC READ_PTR
MOV BH,8
JMP NEXT_SHIFT2
GET_BYTE: CALL READ_ZIP
JNC GET_BITS
JMP SHORT GET_CODE_END
GOT_CODE: DEC BH
MOV SAVE_BYTE,CH
MOV BITS_LEFT,BH
NEG CL
ADD CL,16
SHR AX,CL
CLC
GET_CODE_END: RET
;----------------------------------------------;
CLEAR:
;Mark all nodes as potentially unused.
MOV DX,FREE_NODE
MOV AX,8000H
MOV CX,FIRST_FREE * 2
MOV SI,CX
NEXT_MARK: CMP SI,DX
JZ CK_REF
OR PREFIX[SI],AX
INC SI
INC SI
JMP NEXT_MARK
;Unmark those that are used by other nodes
CK_REF: MOV SI,CX
NEXT_REF: CMP SI,DX
JZ DO_CLEAR
MOV AX,PREFIX[SI]
INC SI
INC SI
AND AX,7FFFH
CMP AX,FIRST_FREE
JB NEXT_REF
MOV DI,AX
SHL DI,1
AND PREFIX[DI],7FFFH
JMP NEXT_REF
;Clear the ones that are still marked
DO_CLEAR: MOV SI,CX
MOV AX,FREE
JMP SHORT NEXT_CLEAR2
NEXT_CLEAR: INC SI
INC SI
NEXT_CLEAR2: CMP SI,DX
JZ FIND_FREE
MOV DI,PREFIX[SI]
AND DI,8000H
JZ NEXT_CLEAR
MOV PREFIX[SI],AX
JMP NEXT_CLEAR
;Find first free node
FIND_FREE: MOV SI,FIRST_FREE * 2
JMP SHORT NEXT_FREE3
NEXT_FREE2: INC SI
INC SI
NEXT_FREE3: CMP PREFIX[SI],AX
JNZ NEXT_FREE2
MOV FREE_NODE,SI
RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed or EOF.
BYTES_TO_READ DW ?,?
READ_PTR DW ?
BYTES_READ DW ?
READ_HANDLE DW ?
READ_ZIP: PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV READ_PTR,0
MOV CX,READ_SIZE
CMP BYTES_TO_READ[2],0
JNZ READ_IT
MOV AX,BYTES_TO_READ[0]
OR AX,AX
STC
JZ READ_ZIP_END
CMP CX,AX
JBE READ_IT
MOV CX,AX
READ_IT: PUSH DS
MOV BX,READ_HANDLE
XOR DX,DX
MOV DS,READ_SEG
MOV AH,3FH
INT 21H
POP DS
JC READ_ZIP_END
CMP AX,CX
STC
JNZ READ_ZIP_END
MOV BYTES_READ,AX
SUB BYTES_TO_READ[0],AX
SBB BYTES_TO_READ[2],0
CLC
READ_ZIP_END: POP DX
POP CX
POP BX
POP AX
RET
;----------------------------------------------;
; INPUT: AL=Char; OUTPUT: CF=1 if failed.
WRITE_PTR DW ?
STORE_CHAR: MOV ES,WRITE_SEG
MOV DI,WRITE_PTR
STOSB
INC WRITE_PTR
MOV BX,RUNNING_CRC_32[0]
MOV DX,RUNNING_CRC_32[2]
XOR AL,BL
XOR AH,AH
MOV BP,AX
SHL BP,1
SHL BP,1
MOV AL,8
NEXT_SHIFT: SAR DX,1 ;DX:BX
RCR BX,1
DEC AL
JNZ NEXT_SHIFT
AND DX,00FFH
XOR BX,WORD PTR CRC_32_TABLE[BP]
XOR DX,WORD PTR CRC_32_TABLE[BP+2]
MOV RUNNING_CRC_32[0],BX
MOV RUNNING_CRC_32[2],DX
CMP DI,WRITE_SIZE
CLC
JNZ STORE_END
CALL WRITE
STORE_END: RET
;----------------------------------------------;
; OUTPUT: CF=1 if failed.
WRITE_HANDLE DW ?
WRITE: PUSH CX
MOV CX,WRITE_PTR
OR CX,CX
JZ WRITE_END
MOV BX,WRITE_HANDLE
XOR DX,DX
PUSH DS
MOV DS,WRITE_SEG
MOV AH,40H
INT 21H
POP DS
MOV WRITE_PTR,0
MOV WRITE_FLAG,1
WRITE_END: POP CX
RET
;----------------------------------------------;
WRITE_FILENAME:MOV DX,OFFSET DIR_NAME
MOV SI,END_FILENAME
PUSH [SI]
MOV BYTE PTR [SI],"$"
CALL PRINT_STRING
POP [SI]
MOV DL,SPACE
MOV AH,2
INT 21H
RET
;----------------------------------------------;
WRITE_CRLF: MOV DX,OFFSET CR_LF
JMP SHORT NEW_LINE
WRITE_CRLFLF: MOV DX,OFFSET CR_LF_LF
NEW_LINE: CALL PRINT_STRING
RET
;----------------------------------------------;
PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET
;----------------------------------------------;
SPINNER: MOV SI,SPIN_INDEX
SUB SI,1
JNC STORE_SPIN
MOV SI,2
STORE_SPIN: MOV SPIN_INDEX,SI
MOV AL,SPINNERS[SI]
SPIN_IT: XOR BH,BH
MOV CX,1
MOV BL,ATTRIBUTE
MOV AH,9
INT 10H
RET
;----------------------------------------------;
CRC_32_TABLE LABEL DWORD
DD 000000000h, 077073096h, 0EE0E612Ch, 0990951BAh, 0076DC419h, 0706AF48Fh, 0E963A535h, 09E6495A3h
DD 00EDB8832h, 079DCB8A4h, 0E0D5E91Eh, 097D2D988h, 009B64C2Bh, 07EB17CBDh, 0E7B82D07h, 090BF1D91h
DD 01DB71064h, 06AB020F2h, 0F3B97148h, 084BE41DEh, 01ADAD47Dh, 06DDDE4EBh, 0F4D4B551h, 083D385C7h
DD 0136C9856h, 0646BA8C0h, 0FD62F97Ah, 08A65C9ECh, 014015C4Fh, 063066CD9h, 0FA0F3D63h, 08D080DF5h
DD 03B6E20C8h, 04C69105Eh, 0D56041E4h, 0A2677172h, 03C03E4D1h, 04B04D447h, 0D20D85FDh, 0A50AB56Bh
DD 035B5A8FAh, 042B2986Ch, 0DBBBC9D6h, 0ACBCF940h, 032D86CE3h, 045DF5C75h, 0DCD60DCFh, 0ABD13D59h
DD 026D930ACh, 051DE003Ah, 0C8D75180h, 0BFD06116h, 021B4F4B5h, 056B3C423h, 0CFBA9599h, 0B8BDA50Fh
DD 02802B89Eh, 05F058808h, 0C60CD9B2h, 0B10BE924h, 02F6F7C87h, 058684C11h, 0C1611DABh, 0B6662D3Dh
DD 076DC4190h, 001DB7106h, 098D220BCh, 0EFD5102Ah, 071B18589h, 006B6B51Fh, 09FBFE4A5h, 0E8B8D433h
DD 07807C9A2h, 00F00F934h, 09609A88Eh, 0E10E9818h, 07F6A0DBBh, 0086D3D2Dh, 091646C97h, 0E6635C01h
DD 06B6B51F4h, 01C6C6162h, 0856530D8h, 0F262004Eh, 06C0695EDh, 01B01A57Bh, 08208F4C1h, 0F50FC457h
DD 065B0D9C6h, 012B7E950h, 08BBEB8EAh, 0FCB9887Ch, 062DD1DDFh, 015DA2D49h, 08CD37CF3h, 0FBD44C65h
DD 04DB26158h, 03AB551CEh, 0A3BC0074h, 0D4BB30E2h, 04ADFA541h, 03DD895D7h, 0A4D1C46Dh, 0D3D6F4FBh
DD 04369E96Ah, 0346ED9FCh, 0AD678846h, 0DA60B8D0h, 044042D73h, 033031DE5h, 0AA0A4C5Fh, 0DD0D7CC9h
DD 05005713Ch, 0270241AAh, 0BE0B1010h, 0C90C2086h, 05768B525h, 0206F85B3h, 0B966D409h, 0CE61E49Fh
DD 05EDEF90Eh, 029D9C998h, 0B0D09822h, 0C7D7A8B4h, 059B33D17h, 02EB40D81h, 0B7BD5C3Bh, 0C0BA6CADh
DD 0EDB88320h, 09ABFB3B6h, 003B6E20Ch, 074B1D29Ah, 0EAD54739h, 09DD277AFh, 004DB2615h, 073DC1683h
DD 0E3630B12h, 094643B84h, 00D6D6A3Eh, 07A6A5AA8h, 0E40ECF0Bh, 09309FF9Dh, 00A00AE27h, 07D079EB1h
DD 0F00F9344h, 08708A3D2h, 01E01F268h, 06906C2FEh, 0F762575Dh, 0806567CBh, 0196C3671h, 06E6B06E7h
DD 0FED41B76h, 089D32BE0h, 010DA7A5Ah, 067DD4ACCh, 0F9B9DF6Fh, 08EBEEFF9h, 017B7BE43h, 060B08ED5h
DD 0D6D6A3E8h, 0A1D1937Eh, 038D8C2C4h, 04FDFF252h, 0D1BB67F1h, 0A6BC5767h, 03FB506DDh, 048B2364Bh
DD 0D80D2BDAh, 0AF0A1B4Ch, 036034AF6h, 041047A60h, 0DF60EFC3h, 0A867DF55h, 0316E8EEFh, 04669BE79h
DD 0CB61B38Ch, 0BC66831Ah, 0256FD2A0h, 05268E236h, 0CC0C7795h, 0BB0B4703h, 0220216B9h, 05505262Fh
DD 0C5BA3BBEh, 0B2BD0B28h, 02BB45A92h, 05CB36A04h, 0C2D7FFA7h, 0B5D0CF31h, 02CD99E8Bh, 05BDEAE1Dh
DD 09B64C2B0h, 0EC63F226h, 0756AA39Ch, 0026D930Ah, 09C0906A9h, 0EB0E363Fh, 072076785h, 005005713h
DD 095BF4A82h, 0E2B87A14h, 07BB12BAEh, 00CB61B38h, 092D28E9Bh, 0E5D5BE0Dh, 07CDCEFB7h, 00BDBDF21h
DD 086D3D2D4h, 0F1D4E242h, 068DDB3F8h, 01FDA836Eh, 081BE16CDh, 0F6B9265Bh, 06FB077E1h, 018B74777h
DD 088085AE6h, 0FF0F6A70h, 066063BCAh, 011010B5Ch, 08F659EFFh, 0F862AE69h, 0616BFFD3h, 0166CCF45h
DD 0A00AE278h, 0D70DD2EEh, 04E048354h, 03903B3C2h, 0A7672661h, 0D06016F7h, 04969474Dh, 03E6E77DBh
DD 0AED16A4Ah, 0D9D65ADCh, 040DF0B66h, 037D83BF0h, 0A9BCAE53h, 0DEBB9EC5h, 047B2CF7Fh, 030B5FFE9h
DD 0BDBDF21Ch, 0CABAC28Ah, 053B39330h, 024B4A3A6h, 0BAD03605h, 0CDD70693h, 054DE5729h, 023D967BFh
DD 0B3667A2Eh, 0C4614AB8h, 05D681B02h, 02A6F2B94h, 0B40BBE37h, 0C30C8EA1h, 05A05DF1Bh, 02D02EF8Dh
EVEN
STACK_POINTER = $ + LOCAL_STACK + (TRIE_SIZE * 2)
PREFIX = OFFSET STACK_POINTER
SUFFIX = OFFSET PREFIX + PREFIX_SIZE
LENGTH_TREE = OFFSET STACK_POINTER + 2
DISTANCE_TREE = OFFSET LENGTH_TREE + LEN_TREE_SIZE + 2
LIT_TREE = OFFSET DISTANCE_TREE + DIST_TREE_SIZE + 2
FOLLOWERS = OFFSET STACK_POINTER
_TEXT ENDS
END START